home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 4 / Meeting Pearls Vol. IV (1996)(GTI - Schatztruhe)[!].iso / Pearls / disk / Devs+Handler / Flat-Handler / Flat-Handler.c < prev    next >
C/C++ Source or Header  |  1994-07-05  |  48KB  |  1,894 lines

  1. ;/*
  2. SC NMINC MCCONS STREQ NOWVRET STRMERGE NOSTKCHK OPTTIME IGNORE=73 Flat-Handler.c
  3. SLINK Flat-Handler.o TO Flat-Handler LIB LIB:sc.lib LIB:amiga.lib SC SD ND
  4. Protect Flat-Handler -e
  5. Copy Flat-Handler L:
  6. Quit
  7. */
  8.  
  9. #include <intuition/intuitionbase.h>
  10. #include <libraries/filehandler.h>
  11. #include <libraries/dosextens.h>
  12. #include <devices/trackdisk.h>
  13. #include <exec/execbase.h>
  14. #include <exec/memory.h>
  15.  
  16. #include <clib/intuition_protos.h>
  17. #include <clib/exec_protos.h>
  18. #include <clib/alib_protos.h>
  19. #include <clib/dos_protos.h>
  20.  
  21. #include <stdarg.h>
  22. #include <string.h>
  23.  
  24. #define DB(x)    ;
  25.  
  26.     /* Standard FS error types. */
  27.  
  28. enum    { ERR_WRITEPROTECT,ERR_NODISK,ERR_UNREADABLE,ERR_WRITEERROR };
  29.  
  30.     /* This is a link node used both for locks and filehandles. */
  31.  
  32. struct FlatNode
  33. {
  34.     struct FlatNode        *fn_Succ;    /* Vanilla node head. */
  35.     struct FlatNode        *fn_Pred;
  36.  
  37.     ULONG             fn_UniqueID;    /* A unique ID. */
  38.  
  39.     LONG             fn_Mode;    /* Either shared or exclusive. */
  40.  
  41.     struct DeviceNode    *fn_DevInfo;    /* Pointer to a device node,
  42.                          * needed by ExNext and the like.
  43.                          */
  44.     ULONG             fn_BlockSize;    /* Size of a block (512 bytes are standard). */
  45.     ULONG             fn_FirstBlock;    /* The first accessible block. */
  46.     ULONG             fn_NumBlocks;    /* Maximum number of available blocks. */
  47.  
  48.     LONG             fn_Position;    /* Current file position in bytes. */
  49.     struct FileLock         fn_Lock;    /* A dummy file lock. */
  50.  
  51.     UBYTE             fn_Name[40];    /* Name of this file. */
  52.  
  53.     struct IOExtTD        *fn_DiskRequest;
  54.     APTR             fn_DiskBuffer;
  55.  
  56.     BYTE             fn_CheckCount;    /* The disk state is checked
  57.                          * every tenth r/w attempt,
  58.                          * this byte keeps the count.
  59.                          */
  60. };
  61.  
  62.     /* This list keeps all the locks and filehandles. */
  63.  
  64. struct List             FlatList;
  65.  
  66.     /* Each open/lock call increments this counter to
  67.      * guarantee that each item receives a unique identifier.
  68.      */
  69.  
  70. ULONG                 UniqueCounter = 0;
  71.  
  72.     /* Shared library identifiers. */
  73.  
  74. struct ExecBase            *SysBase = NULL;
  75. struct DosLibrary        *DOSBase = NULL;
  76. struct IntuitionBase        *IntuitionBase = NULL;
  77.  
  78.     /* Prototypes for this module. */
  79.  
  80. LONG __saveds            HandlerEntry(VOID);
  81.  
  82. LONG __regargs            DoRead(struct FlatNode *FlatNode,LONG *Error,LONG Size,UBYTE *Buffer,struct Process *Caller);
  83. LONG __regargs            DoWrite(struct FlatNode *FlatNode,LONG *Error,LONG Size,UBYTE *Buffer,struct Process *Caller);
  84.  
  85. UBYTE * __regargs        BaseName(UBYTE *String);
  86.  
  87. UBYTE __regargs            Local2Upper(UBYTE c);
  88. UBYTE __regargs            StrCmp(UBYTE *a,UBYTE *b);
  89.  
  90. struct FlatNode * __regargs    FindFlatNodeByID(ULONG UniqueID);
  91. struct FlatNode * __regargs    FindFlatNodeByName(UBYTE *Name);
  92.  
  93. VOID __regargs            BtoCStr(UBYTE *Name,BSTR String,LONG MaxLength);
  94.  
  95. LONG __regargs            ShowRequest(APTR WindowPtr,BYTE Type,UBYTE *Drive);
  96.  
  97. struct DeviceNode * __regargs    FindDevice(struct DeviceNode *LastNode,struct FileSysStartupMsg    **Startup,struct DosEnvec **DosEnvec,UBYTE *Name);
  98.  
  99. VOID __regargs            DeleteNode(struct FlatNode *FlatNode);
  100. struct FlatNode * __regargs    CreateNode(struct MsgPort *DiskPort,LONG Type,UBYTE *Name);
  101.  
  102. VOID __regargs            ReturnPacket(struct DosPacket *Packet,ULONG Res1,ULONG Res2,struct Process *HandlerProc);
  103. struct DosPacket * __regargs    WaitPacket(struct Process *HandlerProc);
  104.  
  105.     /* HandlerEntry():
  106.      *
  107.      *    Entry point for this module.
  108.      */
  109.  
  110. LONG __saveds
  111. HandlerEntry()
  112. {
  113.     struct Process            *HandlerProc;
  114.  
  115.     struct FileHandle        *FileHandle;
  116.     struct FileLock            *FileLock;
  117.  
  118.     LONG                 ReadBytes,WriteBytes,Bytes;
  119.     LONG                 NewPosition;
  120.     struct FileInfoBlock        *FileInfo;
  121.     struct InfoData            *InfoData;
  122.     UBYTE                *FileName;
  123.     UBYTE                 NameBuffer[257];
  124.  
  125.     struct DosPacket        *FlatPacket;
  126.     struct DeviceNode        *FlatDevNode;
  127.     struct DeviceList        *VolumeNode;
  128.  
  129.     struct FlatNode            *FlatNode;
  130.     struct MsgPort            *DiskPort;
  131.  
  132.     struct DateStamp         CreationDate;
  133.     UBYTE __aligned             VolumeName[264];
  134.  
  135.         /* Set up SysBase. */
  136.  
  137.     SysBase = *(struct ExecBase **)4;
  138.  
  139.         /* Know who we are. */
  140.  
  141.     HandlerProc = (struct Process *)SysBase -> ThisTask;
  142.  
  143.         /* Started from Shell (oops!)? */
  144.  
  145.     if(!HandlerProc -> pr_CLI)
  146.     {
  147.             /* Wait for startup packet. */
  148.  
  149.         FlatPacket = WaitPacket(HandlerProc);
  150.  
  151.             /* Clear the list. */
  152.  
  153.         NewList(&FlatList);
  154.  
  155.             /* Pick up the pointer to our DeviceNode. */
  156.  
  157.         FlatDevNode = (struct DeviceNode *)BADDR(FlatPacket -> dp_Arg3);
  158.  
  159.             /* Install ourselves at the other hand. */
  160.  
  161.         FlatDevNode -> dn_Task = &HandlerProc -> pr_MsgPort;
  162.  
  163.         if(!(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",0)))
  164.         {
  165.             ReturnPacket(FlatPacket,DOSFALSE,FlatPacket -> dp_Res2,HandlerProc);
  166.             goto FallOff;
  167.         }
  168.  
  169.         DateStamp(&CreationDate);
  170.  
  171.             /* Open Intuition; we might want to put up
  172.              * auto-requesters.
  173.              */
  174.  
  175.         if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0)))
  176.         {
  177.             ReturnPacket(FlatPacket,DOSFALSE,FlatPacket -> dp_Res2,HandlerProc);
  178.             goto FallOff;
  179.         }
  180.  
  181.         if(!(DiskPort = CreatePort(NULL,0)))
  182.         {
  183.             ReturnPacket(FlatPacket,DOSFALSE,FlatPacket -> dp_Res2,HandlerProc);
  184.             goto FallOff;
  185.         }
  186.  
  187.         if(!(VolumeNode = (struct DeviceList *)AllocMem(sizeof(struct DeviceList),MEMF_ANY | MEMF_CLEAR)))
  188.         {
  189.             ReturnPacket(FlatPacket,DOSFALSE,FlatPacket -> dp_Res2,HandlerProc);
  190.             goto FallOff;
  191.         }
  192.  
  193.         FileName = VolumeName;
  194.  
  195.         *(ULONG *)FileName = 264;
  196.  
  197.         FileName += 4;
  198.  
  199.         strcpy(FileName,"\7Devices");
  200.  
  201.         VolumeNode -> dl_Type        = DLT_VOLUME;
  202.         VolumeNode -> dl_Task        = &HandlerProc -> pr_MsgPort;
  203.         VolumeNode -> dl_DiskType    = ID_DOS_DISK;
  204.         VolumeNode -> dl_Name        = MKBADDR(FileName);
  205.         VolumeNode -> dl_VolumeDate    = CreationDate;
  206.  
  207.         Forbid();
  208.  
  209. //        I removed the following lines because i only use flat for AMAX
  210.  
  211.         VolumeNode -> dl_Next = ((struct DosInfo *)BADDR(((struct RootNode *)DOSBase -> dl_Root) -> rn_Info)) -> di_DevInfo;
  212.  
  213.         ((struct DosInfo *)BADDR(((struct RootNode *)DOSBase -> dl_Root) -> rn_Info)) -> di_DevInfo = MKBADDR(VolumeNode);
  214.  
  215.         Permit();
  216.  
  217.             /* Initialization finished, now return the
  218.              * startup packet.
  219.              */
  220.  
  221.         ReturnPacket(FlatPacket,DOSTRUE,FlatPacket -> dp_Res2,HandlerProc);
  222.  
  223.             /* Go into loop waiting for data packets. */
  224.  
  225.         FOREVER
  226.         {
  227.                 /* Wait for packet. */
  228.  
  229.             FlatPacket = WaitPacket(HandlerProc);
  230.  
  231.             DB(kprintf("Packet from \"%s\"\n",((struct Task *)FlatPacket -> dp_Port -> mp_SigTask) -> tc_Node . ln_Name));
  232.  
  233.                 /* Examine the packet type. */
  234.  
  235.             switch(FlatPacket -> dp_Type)
  236.             {
  237.                 case ACTION_RENAME_DISK:
  238.  
  239.                     DB(kprintf("ACTION_RENAME_DISK\n"));
  240.  
  241.                     if(FlatPacket -> dp_Arg1)
  242.                     {
  243.                         UBYTE *NewName = (UBYTE *)BADDR(FlatPacket -> dp_Arg1);
  244.  
  245.                         if(NewName[0])
  246.                         {
  247.                             LONG Len = *NewName++;
  248.  
  249.                             if(Len > 256)
  250.                                 Len = 256;
  251.  
  252.                             FileName = VolumeName + 4;
  253.  
  254.                             Forbid();
  255.  
  256.                             *FileName++ = Len;
  257.  
  258.                             memcpy(FileName,NewName,Len);
  259.  
  260.                             FileName[Len] = 0;
  261.  
  262.                             Permit();
  263.  
  264.                             ReturnPacket(FlatPacket,DOSTRUE,NULL,HandlerProc);
  265.                         }
  266.                         else
  267.                             ReturnPacket(FlatPacket,DOSFALSE,ERROR_INVALID_COMPONENT_NAME,HandlerProc);
  268.                     }
  269.                     else
  270.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_INVALID_COMPONENT_NAME,HandlerProc);
  271.  
  272.                     break;
  273.  
  274.                 case ACTION_PARENT:
  275.  
  276.                     DB(kprintf("ACTION_PARENT\n"));
  277.  
  278.                     if(FlatPacket -> dp_Arg1)
  279.                     {
  280.                         if(FlatNode = FindFlatNodeByID(((struct FileLock *)BADDR(FlatPacket -> dp_Arg1)) -> fl_Key))
  281.                         {
  282.                             if(FlatNode -> fn_Name[1])
  283.                             {
  284.                                 if(FlatNode = CreateNode(DiskPort,SHARED_LOCK,NULL))
  285.                                 {
  286.                                     AddTail(&FlatList,(struct Node *)FlatNode);
  287.  
  288.                                     FlatNode -> fn_Lock . fl_Access    = SHARED_LOCK;
  289.                                     FlatNode -> fn_Lock . fl_Task    = &HandlerProc -> pr_MsgPort;
  290.                                     FlatNode -> fn_Lock . fl_Volume    = MKBADDR(VolumeNode);
  291.                                     FlatNode -> fn_Lock . fl_Key    = FlatNode -> fn_UniqueID;
  292.  
  293.                                     ReturnPacket(FlatPacket,MKBADDR(&FlatNode -> fn_Lock),NULL,HandlerProc);
  294.                                 }
  295.                                 else
  296.                                     ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  297.                             }
  298.                             else
  299.                                 ReturnPacket(FlatPacket,0,0,HandlerProc);
  300.                         }
  301.                         else
  302.                             ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  303.                     }
  304.                     else
  305.                         ReturnPacket(FlatPacket,0,0,HandlerProc);
  306.  
  307.                     break;
  308.  
  309.                 case ACTION_INFO:
  310.  
  311.                     DB(kprintf("ACTION_INFO\n"));
  312.  
  313.                     if(InfoData = (struct InfoData *)BADDR(FlatPacket -> dp_Arg2))
  314.                     {
  315.                         memset(InfoData,0,sizeof(struct InfoData));
  316.  
  317.                         InfoData -> id_DiskState    = ID_VALIDATED;
  318.                         InfoData -> id_NumBlocks    = 2;
  319.                         InfoData -> id_NumBlocksUsed    = 2;
  320.                         InfoData -> id_BytesPerBlock    = 512;
  321.                         InfoData -> id_DiskType        = ID_DOS_DISK;
  322.                         InfoData -> id_VolumeNode    = MKBADDR(VolumeNode);
  323.                         InfoData -> id_InUse        = DOSTRUE;
  324.  
  325.                         ReturnPacket(FlatPacket,DOSTRUE,NULL,HandlerProc);
  326.                     }
  327.                     else
  328.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  329.  
  330.                     break;
  331.  
  332.                 case ACTION_DISK_INFO:
  333.  
  334.                     DB(kprintf("ACTION_DISK_INFO\n"));
  335.  
  336.                     if(InfoData = (struct InfoData *)BADDR(FlatPacket -> dp_Arg1))
  337.                     {
  338.                         memset(InfoData,0,sizeof(struct InfoData));
  339.  
  340.                         InfoData -> id_DiskState    = ID_VALIDATED;
  341.                         InfoData -> id_NumBlocks    = 2;
  342.                         InfoData -> id_NumBlocksUsed    = 2;
  343.                         InfoData -> id_BytesPerBlock    = 512;
  344.                         InfoData -> id_DiskType        = ID_DOS_DISK;
  345.                         InfoData -> id_VolumeNode    = MKBADDR(VolumeNode);
  346.                         InfoData -> id_InUse        = DOSTRUE;
  347.  
  348.                         ReturnPacket(FlatPacket,DOSTRUE,NULL,HandlerProc);
  349.                     }
  350.                     else
  351.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  352.  
  353.                     break;
  354.  
  355.                 case ACTION_CURRENT_VOLUME:
  356.  
  357.                     DB(kprintf("ACTION_CURRENT_VOLUME\n"));
  358.  
  359.                     ReturnPacket(FlatPacket,MKBADDR(VolumeNode),NULL,HandlerProc);
  360.                     break;
  361.  
  362.                 case ACTION_IS_FILESYSTEM:
  363.  
  364.                     DB(kprintf("ACTION_IS_FILESYSTEM\n"));
  365.  
  366.                     ReturnPacket(FlatPacket,DOSTRUE,NULL,HandlerProc);
  367.                     break;
  368.  
  369.                     /* Obtain a filelock. */
  370.  
  371.                 case ACTION_LOCATE_OBJECT:
  372.  
  373.                         /* Convert the file name. */
  374.  
  375.                     BtoCStr(NameBuffer,FlatPacket -> dp_Arg2,256);
  376.  
  377.                     DB(kprintf("ACTION_LOCATE_OBJECT \"%s\" %ld\n",NameBuffer,FlatPacket -> dp_Arg3));
  378.  
  379.                         /* Are we to return a lock
  380.                          * to a file or a lock to the
  381.                          * root directory?
  382.                          */
  383.  
  384.                     if(FileName = BaseName(NameBuffer))
  385.                     {
  386.                         DB(kprintf("base name \"%s\"\n",FileName));
  387.  
  388.                             /* Look for a file of this name. */
  389.  
  390.                         if(FlatNode = FindFlatNodeByName(FileName))
  391.                         {
  392.                                 /* See if the file is currently locked. */
  393.  
  394.                             if((FlatNode -> fn_Mode != FlatPacket -> dp_Arg3) || (FlatPacket -> dp_Arg3 == EXCLUSIVE_LOCK && FlatNode -> fn_Mode == EXCLUSIVE_LOCK))
  395.                             {
  396.                                 ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_IN_USE,HandlerProc);
  397.                                 break;
  398.                             }
  399.                         }
  400.  
  401.                             /* Create a new item and add it to the list. */
  402.  
  403.                         if(FlatNode = CreateNode(DiskPort,FlatPacket -> dp_Arg3,FileName))
  404.                         {
  405.                             AddTail(&FlatList,(struct Node *)FlatNode);
  406.  
  407.                                 /* Initialize the default data so DOS will
  408.                                  * get along with us.
  409.                                  */
  410.  
  411.                             FlatNode -> fn_Lock . fl_Access    = FlatPacket -> dp_Arg3;
  412.                             FlatNode -> fn_Lock . fl_Task    = &HandlerProc -> pr_MsgPort;
  413.                             FlatNode -> fn_Lock . fl_Volume    = MKBADDR(VolumeNode);
  414.                             FlatNode -> fn_Lock . fl_Key    = FlatNode -> fn_UniqueID;
  415.  
  416.                             strcpy(&FlatNode -> fn_Name[1],FileName);
  417.  
  418.                             ReturnPacket(FlatPacket,MKBADDR(&FlatNode -> fn_Lock),NULL,HandlerProc);
  419.                         }
  420.                         else
  421.                             ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  422.                     }
  423.                     else
  424.                     {
  425.                         if(FlatNode = CreateNode(DiskPort,FlatPacket -> dp_Arg3,NULL))
  426.                         {
  427.                             AddTail(&FlatList,(struct Node *)FlatNode);
  428.  
  429.                             FlatNode -> fn_Lock . fl_Access    = FlatPacket -> dp_Arg3;
  430.                             FlatNode -> fn_Lock . fl_Task    = &HandlerProc -> pr_MsgPort;
  431.                             FlatNode -> fn_Lock . fl_Volume    = MKBADDR(VolumeNode);
  432.                             FlatNode -> fn_Lock . fl_Key    = FlatNode -> fn_UniqueID;
  433.  
  434.                             ReturnPacket(FlatPacket,MKBADDR(&FlatNode -> fn_Lock),NULL,HandlerProc);
  435.                         }
  436.                         else
  437.                             ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  438.                     }
  439.  
  440.                     break;
  441.  
  442.                     /* Free a lock obtained above. */
  443.  
  444.                 case ACTION_FREE_LOCK:
  445.  
  446.                     DB(kprintf("ACTION_FREE_LOCK\n"));
  447.  
  448.                         /* Is the lock part of the list? */
  449.  
  450.                     if(FlatPacket -> dp_Arg1)
  451.                     {
  452.                         if(FlatNode = FindFlatNodeByID(((struct FileLock *)BADDR(FlatPacket -> dp_Arg1)) -> fl_Key))
  453.                         {
  454.                             Remove((struct Node *)FlatNode);
  455.  
  456.                             DeleteNode(FlatNode);
  457.                         }
  458.                     }
  459.  
  460.                     ReturnPacket(FlatPacket,DOSTRUE,0,HandlerProc);
  461.  
  462.                     break;
  463.  
  464.                     /* Duplicate a shared lock. */
  465.  
  466.                 case ACTION_COPY_DIR:
  467.  
  468.                     DB(kprintf("ACTION_COPY_DIR\n"));
  469.  
  470.                         /* Are we to duplicate a non-ZERO lock? */
  471.  
  472.                     if(FlatPacket -> dp_Arg1)
  473.                     {
  474.                         FileLock = (struct FileLock *)BADDR(FlatPacket -> dp_Arg1);
  475.  
  476.                             /* Try to find the corresponding list entry. */
  477.  
  478.                         if(FlatNode = FindFlatNodeByID(FileLock -> fl_Key))
  479.                         {
  480.                                 /* Only shared locks may be duplicated. */
  481.  
  482.                             if(FlatNode -> fn_Mode == EXCLUSIVE_LOCK)
  483.                                 ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_IN_USE,HandlerProc);
  484.                             else
  485.                             {
  486.                                 struct FlatNode *AnotherNode;
  487.  
  488.                                     /* Create a new node. */
  489.  
  490.                                 if(FlatNode -> fn_Name[1])
  491.                                     AnotherNode = CreateNode(DiskPort,SHARED_LOCK,&FlatNode -> fn_Name[1]);
  492.                                 else
  493.                                     AnotherNode = CreateNode(DiskPort,SHARED_LOCK,NULL);
  494.  
  495.                                     /* Did we get what we wanted? */
  496.  
  497.                                 if(AnotherNode)
  498.                                 {
  499.                                         /* Not quite so unique I suppose. */
  500.  
  501.                                     AnotherNode -> fn_UniqueID = FlatNode -> fn_UniqueID;
  502.  
  503.                                         /* Add the freshly created lock
  504.                                          * to the list.
  505.                                          */
  506.  
  507.                                     AddTail(&FlatList,(struct Node *)AnotherNode);
  508.  
  509.                                         /* Fill in the Lock data. */
  510.  
  511.                                     AnotherNode -> fn_Lock . fl_Access    = SHARED_LOCK;
  512.                                     AnotherNode -> fn_Lock . fl_Task    = &HandlerProc -> pr_MsgPort;
  513.                                     AnotherNode -> fn_Lock . fl_Volume    = MKBADDR(VolumeNode);
  514.                                     AnotherNode -> fn_Lock . fl_Key        = AnotherNode -> fn_UniqueID;
  515.  
  516.                                         /* Successful return. */
  517.  
  518.                                     ReturnPacket(FlatPacket,MKBADDR(&AnotherNode -> fn_Lock),NULL,HandlerProc);
  519.                                 }
  520.                                 else
  521.                                     ReturnPacket(FlatPacket,DOSFALSE,ERROR_NO_FREE_STORE,HandlerProc);
  522.                             }
  523.                         }
  524.                         else
  525.                             ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  526.                     }
  527.                     else
  528.                         ReturnPacket(FlatPacket,0,0,HandlerProc);
  529.  
  530.                     break;
  531.  
  532.                     /* Examine a file. */
  533.  
  534.                 case ACTION_EXAMINE_OBJECT:
  535.  
  536.                     DB(kprintf("ACTION_EXAMINE_OBJECT\n"));
  537.  
  538.                         /* Are both identifiers valid? */
  539.  
  540.                     if((FileLock = (struct FileLock *)BADDR(FlatPacket -> dp_Arg1)) && (FileInfo = (struct FileInfoBlock *)BADDR(FlatPacket -> dp_Arg2)))
  541.                     {
  542.                         BYTE Success = FALSE;
  543.  
  544.                             /* Can we find the item? */
  545.  
  546.                         if(FlatNode = FindFlatNodeByID(FileLock -> fl_Key))
  547.                         {
  548.                             DB(kprintf("name \"%s\"\n",&FlatNode -> fn_Name[1]));
  549.  
  550.                                 /* Is it a file or a directory? */
  551.  
  552.                             if(FlatNode -> fn_Name[1])
  553.                             {
  554.                                 struct FileSysStartupMsg    *Startup;
  555.                                 struct DosEnvec            *DosEnvec;
  556.  
  557.                                     /* Find the approriate device. */
  558.  
  559.                                 if(FlatNode -> fn_DevInfo = FindDevice(NULL,&Startup,&DosEnvec,&FlatNode -> fn_Name[1]))
  560.                                 {
  561.                                     struct IOExtTD *DiskRequest;
  562.  
  563.                                     if(DiskRequest = (struct IOExtTD *)CreateExtIO(DiskPort,sizeof(struct IOExtTD)))
  564.                                     {
  565.                                         BtoCStr(NameBuffer,Startup -> fssm_Device,256);
  566.  
  567.                                         if(!OpenDevice(NameBuffer,Startup -> fssm_Unit,DiskRequest,Startup -> fssm_Flags))
  568.                                         {
  569.                                                 /* We are actually faking part of the data
  570.                                                  * to be returned in the fileinfoblock.
  571.                                                  * This isn't Unix and there are only two
  572.                                                  * kinds of directory entries: files and
  573.                                                  * directories. The protection bits are by
  574.                                                  * default configured to mimic the state of
  575.                                                  * the corresponding drive. If not write-
  576.                                                  * enabled, the file will have the write
  577.                                                  * access-bit cleared, if there is no disk
  578.                                                  * in the drive, the read bit will be cleared,
  579.                                                  * the file size will be zero as well.
  580.                                                  */
  581.  
  582.                                             memset(FileInfo,0,sizeof(struct FileInfoBlock));
  583.  
  584.                                             FileInfo -> fib_DiskKey        = FileLock -> fl_Key;
  585.                                             FileInfo -> fib_DirEntryType    = ST_FILE;
  586.                                             FileInfo -> fib_Protection    = FIBF_EXECUTE|FIBF_DELETE;
  587.                                             FileInfo -> fib_Size        = (DosEnvec -> de_HighCyl - DosEnvec -> de_LowCyl + 1) * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces * (DosEnvec -> de_SizeBlock << 2);
  588.                                             FileInfo -> fib_NumBlocks    = (DosEnvec -> de_HighCyl - DosEnvec -> de_LowCyl + 1) * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces;
  589.                                             FileInfo -> fib_Date        = CreationDate;
  590.  
  591.                                             memcpy(FileInfo -> fib_FileName,BADDR(FlatNode -> fn_DevInfo -> dn_Name),((UBYTE *)BADDR(FlatNode -> fn_DevInfo -> dn_Name))[0] + 1);
  592.  
  593.                                             DiskRequest -> iotd_Req . io_Command = TD_PROTSTATUS;
  594.  
  595.                                             if(!DoIO(DiskRequest))
  596.                                             {
  597.                                                 if(DiskRequest -> iotd_Req . io_Actual)
  598.                                                     FileInfo -> fib_Protection |= FIBF_WRITE;
  599.                                             }
  600.  
  601.                                             DiskRequest -> iotd_Req . io_Command = TD_CHANGESTATE;
  602.  
  603.                                             if(!DoIO(DiskRequest))
  604.                                             {
  605.                                                 if(DiskRequest -> iotd_Req . io_Actual)
  606.                                                 {
  607.                                                     FileInfo -> fib_Protection |= FIBF_READ|FIBF_WRITE;
  608.  
  609.                                                     FileInfo -> fib_Size = FileInfo -> fib_NumBlocks = 0;
  610.                                                 }
  611.                                             }
  612.  
  613.                                             Success = TRUE;
  614.  
  615.                                             CloseDevice(DiskRequest);
  616.                                         }
  617.  
  618.                                         DeleteExtIO(DiskRequest);
  619.                                     }
  620.                                 }
  621.                             }
  622.                             else
  623.                             {
  624.                                     /* This is very much the same as above,
  625.                                      * but this time it's the root directory
  626.                                      * we will create.
  627.                                      */
  628.  
  629.                                 memset(FileInfo,0,sizeof(struct FileInfoBlock));
  630.  
  631.                                 FileInfo -> fib_DiskKey        = FileLock -> fl_Key;
  632.                                 FileInfo -> fib_DirEntryType    = ST_ROOT;
  633.                                 FileInfo -> fib_Protection    = FIBF_EXECUTE;
  634.                                 FileInfo -> fib_Size        = 0;
  635.                                 FileInfo -> fib_NumBlocks    = 0;
  636.                                 FileInfo -> fib_Date        = CreationDate;
  637.  
  638.                                 strcpy(FileInfo -> fib_FileName,VolumeName + 4);
  639.  
  640.                                 Success = TRUE;
  641.                             }
  642.                         }
  643.  
  644.                         if(Success)
  645.                             ReturnPacket(FlatPacket,DOSTRUE,NULL,HandlerProc);
  646.                         else
  647.                             ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  648.                     }
  649.                     else
  650.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  651.  
  652.                     break;
  653.  
  654.                     /* Examine a file. */
  655.  
  656.                 case ACTION_EXAMINE_FH:
  657.  
  658.                     DB(kprintf("ACTION_EXAMINE_FH\n"));
  659.  
  660.                         /* Both FIB buffer && FileHandle valid? */
  661.  
  662.                     if(FileInfo = (struct FileInfoBlock *)BADDR(FlatPacket -> dp_Arg2))
  663.                     {
  664.                         BYTE Success = FALSE;
  665.  
  666.                         DB(kprintf("FileInfo: %08lx, NodeID: %ld \n",FileInfo,FlatPacket -> dp_Arg1));
  667.  
  668.                             /* Can we find the item? */
  669.  
  670.                         if(FlatNode = FindFlatNodeByID(FlatPacket -> dp_Arg1))
  671.                         {
  672.                             struct FileSysStartupMsg    *Startup;
  673.                             struct DosEnvec            *DosEnvec;
  674.  
  675.                             DB(kprintf("name \"%s\"\n",&FlatNode -> fn_Name[1]));
  676.  
  677.                                 /* Find the approriate device. */
  678.  
  679.                             if(FlatNode -> fn_DevInfo = FindDevice(NULL,&Startup,&DosEnvec,&FlatNode -> fn_Name[1]))
  680.                             {
  681.                                 struct IOExtTD *DiskRequest;
  682.  
  683.                                 DB(kprintf("DevInfo: %08lx \n",FlatNode -> fn_DevInfo));
  684.  
  685.                                 if(DiskRequest = (struct IOExtTD *)CreateExtIO(DiskPort,sizeof(struct IOExtTD)))
  686.                                 {
  687.                                     DB(kprintf("DiskRequest: %08lx \n",DiskRequest));
  688.  
  689.                                     BtoCStr(NameBuffer,Startup -> fssm_Device,256);
  690.  
  691.                                     if(!OpenDevice(NameBuffer,Startup -> fssm_Unit,DiskRequest,Startup -> fssm_Flags))
  692.                                     {
  693.                                             /* We are actually faking part of the data
  694.                                              * to be returned in the fileinfoblock.
  695.                                              * This isn't Unix and there are only two
  696.                                              * kinds of directory entries: files and
  697.                                              * directories. The protection bits are by
  698.                                              * default configured to mimic the state of
  699.                                              * the corresponding drive. If not write-
  700.                                              * enabled, the file will have the write
  701.                                              * access-bit cleared, if there is no disk
  702.                                              * in the drive, the read bit will be cleared,
  703.                                              * the file size will be zero as well.
  704.                                              */
  705.  
  706.                                         memset(FileInfo,0,sizeof(struct FileInfoBlock));
  707.  
  708.                                         FileInfo -> fib_DiskKey        = 0;    // FileLock -> fl_Key;
  709.                                         FileInfo -> fib_DirEntryType    = ST_FILE;
  710.                                         FileInfo -> fib_Protection    = FIBF_EXECUTE|FIBF_DELETE;
  711.                                         FileInfo -> fib_Size        = (DosEnvec -> de_HighCyl - DosEnvec -> de_LowCyl + 1) * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces * (DosEnvec -> de_SizeBlock << 2);
  712.                                         FileInfo -> fib_NumBlocks    = (DosEnvec -> de_HighCyl - DosEnvec -> de_LowCyl + 1) * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces;
  713.                                         FileInfo -> fib_Date        = CreationDate;
  714.  
  715.  
  716.                                         DB(kprintf("FileSize: %08lx \n",FileInfo ->fib_Size));
  717.     
  718.                                         memcpy(FileInfo -> fib_FileName,BADDR(FlatNode -> fn_DevInfo -> dn_Name),((UBYTE *)BADDR(FlatNode -> fn_DevInfo -> dn_Name))[0] + 1);
  719.  
  720.                                         DiskRequest -> iotd_Req . io_Command = TD_PROTSTATUS;
  721.  
  722.                                         if(!DoIO(DiskRequest))
  723.                                         {
  724.                                             if(DiskRequest -> iotd_Req . io_Actual)
  725.                                                 FileInfo -> fib_Protection |= FIBF_WRITE;
  726.                                         }
  727.  
  728.                                         DiskRequest -> iotd_Req . io_Command = TD_CHANGESTATE;
  729.  
  730.                                         if(!DoIO(DiskRequest))
  731.                                         {
  732.                                             if(DiskRequest -> iotd_Req . io_Actual)
  733.                                             {
  734.                                                 FileInfo -> fib_Protection |= FIBF_READ|FIBF_WRITE;
  735.  
  736.                                                 FileInfo -> fib_Size = FileInfo -> fib_NumBlocks = 0;
  737.                                             }
  738.                                         }
  739.  
  740.                                         Success = TRUE;
  741.  
  742.                                         CloseDevice(DiskRequest);
  743.                                     }
  744.  
  745.                                     DeleteExtIO(DiskRequest);
  746.                                 }
  747.                             }
  748.                         }
  749.  
  750.                         if(Success)
  751.                             ReturnPacket(FlatPacket,DOSTRUE,NULL,HandlerProc);
  752.                         else
  753.                             ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  754.                     }
  755.                     else
  756.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  757.  
  758.                     break;
  759.  
  760.                 case ACTION_CREATE_DIR:
  761.  
  762.                     DB(kprintf("ACTION_CREATE_DIR\n"));
  763.  
  764.                     ReturnPacket(FlatPacket,DOSFALSE,ERROR_DISK_FULL,HandlerProc);
  765.                     break;
  766.  
  767.                 case ACTION_DELETE_OBJECT:
  768.  
  769.                     DB(kprintf("ACTION_DELETE_OBJECT\n"));
  770.  
  771.                     ReturnPacket(FlatPacket,DOSFALSE,ERROR_DELETE_PROTECTED,HandlerProc);
  772.                     break;
  773.  
  774.                 case ACTION_RENAME_OBJECT:
  775.                 case ACTION_SET_PROTECT:
  776.                 case ACTION_SET_COMMENT:
  777.                 case ACTION_SET_DATE:
  778.  
  779.                     DB(kprintf("ACTION_WUSEL\n"));
  780.  
  781.                     ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_IN_USE,HandlerProc);
  782.                     break;
  783.  
  784.                     /* Examine the next directory entry (if available). */
  785.  
  786.                 case ACTION_EXAMINE_NEXT:
  787.  
  788.                     DB(kprintf("ACTION_EXAMINE_NEXT\n"));
  789.  
  790.                         /* This works very much the same as above, with the
  791.                          * exception that we are trying to gather information
  792.                          * on the next available DosList Device entry.
  793.                          */
  794.  
  795.                     if((FileLock = (struct FileLock *)BADDR(FlatPacket -> dp_Arg1)) && (FileInfo = (struct FileInfoBlock *)BADDR(FlatPacket -> dp_Arg2)))
  796.                     {
  797.                         BYTE Success = FALSE;
  798.  
  799.                         if(FlatNode = FindFlatNodeByID(FileLock -> fl_Key))
  800.                         {
  801.                             struct FileSysStartupMsg    *Startup;
  802.                             struct DosEnvec            *DosEnvec;
  803.  
  804.                             DB(kprintf("name \"%s\"\n",&FlatNode -> fn_Name[1]));
  805.  
  806.                             if(FlatNode -> fn_DevInfo = FindDevice(FlatNode -> fn_DevInfo,&Startup,&DosEnvec,NULL))
  807.                             {
  808.                                 struct IOExtTD *DiskRequest;
  809.  
  810.                                 if(DiskRequest = (struct IOExtTD *)CreateExtIO(DiskPort,sizeof(struct IOExtTD)))
  811.                                 {
  812.                                     BtoCStr(NameBuffer,Startup -> fssm_Device,256);
  813.  
  814.                                     if(!OpenDevice(NameBuffer,Startup -> fssm_Unit,DiskRequest,Startup -> fssm_Flags))
  815.                                     {
  816.                                         memset(FileInfo,0,sizeof(struct FileInfoBlock));
  817.  
  818.                                         FileInfo -> fib_DiskKey        = FileLock -> fl_Key;
  819.                                         FileInfo -> fib_DirEntryType    = ST_FILE;
  820.                                         FileInfo -> fib_Protection    = FIBF_EXECUTE|FIBF_DELETE;
  821.                                         FileInfo -> fib_Size        = (DosEnvec -> de_HighCyl - DosEnvec -> de_LowCyl + 1) * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces * (DosEnvec -> de_SizeBlock << 2);
  822.                                         FileInfo -> fib_NumBlocks    = (DosEnvec -> de_HighCyl - DosEnvec -> de_LowCyl + 1) * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces;
  823.                                         FileInfo -> fib_Date        = CreationDate;
  824.  
  825.                                         memcpy(FileInfo -> fib_FileName,BADDR(FlatNode -> fn_DevInfo -> dn_Name),((UBYTE *)BADDR(FlatNode -> fn_DevInfo -> dn_Name))[0] + 1);
  826.  
  827.                                         DiskRequest -> iotd_Req . io_Command = TD_PROTSTATUS;
  828.  
  829.                                         if(!DoIO(DiskRequest))
  830.                                         {
  831.                                             if(DiskRequest -> iotd_Req . io_Actual)
  832.                                                 FileInfo -> fib_Protection |= FIBF_WRITE;
  833.                                         }
  834.  
  835.                                         DiskRequest -> iotd_Req . io_Command = TD_CHANGESTATE;
  836.  
  837.                                         if(!DoIO(DiskRequest))
  838.                                         {
  839.                                             if(DiskRequest -> iotd_Req . io_Actual)
  840.                                             {
  841.                                                 FileInfo -> fib_Protection |= FIBF_READ|FIBF_WRITE;
  842.  
  843.                                                 FileInfo -> fib_Size = FileInfo -> fib_NumBlocks = 0;
  844.                                             }
  845.                                         }
  846.  
  847.                                         Success = TRUE;
  848.  
  849.                                         CloseDevice(DiskRequest);
  850.                                     }
  851.  
  852.                                     DeleteExtIO(DiskRequest);
  853.                                 }
  854.                             }
  855.                             else
  856.                             {
  857.                                 ReturnPacket(FlatPacket,DOSFALSE,ERROR_NO_MORE_ENTRIES,HandlerProc);
  858.  
  859.                                 break;
  860.                             }
  861.                         }
  862.  
  863.                         if(Success)
  864.                             ReturnPacket(FlatPacket,DOSTRUE,NULL,HandlerProc);
  865.                         else
  866.                             ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  867.                     }
  868.                     else
  869.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  870.  
  871.                     break;
  872.  
  873.                     /* Open any file for reading/writing. */
  874.  
  875.                 case ACTION_FINDINPUT:
  876.                 case ACTION_FINDOUTPUT:
  877.                 case ACTION_FINDUPDATE:
  878.  
  879.                         /* Convert the file name. */
  880.  
  881.                     BtoCStr(NameBuffer,FlatPacket -> dp_Arg3,256);
  882.  
  883.                     DB(kprintf("ACTION_FIND... \"%s\"\n",NameBuffer));
  884.  
  885.                     if(FileName = BaseName(NameBuffer))
  886.                     {
  887.                         LONG Mode;
  888.  
  889.                         DB(kprintf("base name \"%s\"\n",FileName));
  890.  
  891.                             /* Only the MODE_OLDFILE type allows
  892.                              * shared data access.
  893.                              */
  894.  
  895.                         if(FlatPacket -> dp_Type == ACTION_FINDINPUT)
  896.                             Mode = SHARED_LOCK;
  897.                         else
  898.                             Mode = EXCLUSIVE_LOCK;
  899.  
  900.                         FileHandle = (struct FileHandle *)BADDR(FlatPacket -> dp_Arg1);
  901.  
  902.                             /* Is there already a lock or filehandle by this
  903.                              * name?
  904.                              */
  905.  
  906.                         if(FlatNode = FindFlatNodeByName(FileName))
  907.                         {
  908.                                 /* If so, is it locked? */
  909.  
  910.                             if((FlatNode -> fn_Mode != Mode) || (Mode == EXCLUSIVE_LOCK && FlatNode -> fn_Mode == EXCLUSIVE_LOCK))
  911.                             {
  912.                                 ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_IN_USE,HandlerProc);
  913.                                 break;
  914.                             }
  915.                             else
  916.                                 ReturnPacket(FlatPacket,DOSTRUE,NULL,HandlerProc);
  917.  
  918.                         }
  919.  
  920.                             /* Create a new list entry. */
  921.  
  922.                         if(FlatNode = CreateNode(DiskPort,Mode,FileName))
  923.                         {
  924.                             AddTail(&FlatList,(struct Node *)FlatNode);
  925.  
  926.                             FileHandle -> fh_Arg1 = FlatNode -> fn_UniqueID;
  927.  
  928.                             DB(kprintf("UniqueID %ld\n",FileHandle->fh_Arg1));
  929.  
  930.                                 /* Turn on the disk motor. */
  931.  
  932.                             FlatNode -> fn_DiskRequest -> iotd_Req . io_Command    = TD_MOTOR;
  933.                             FlatNode -> fn_DiskRequest -> iotd_Req . io_Length    = 1;
  934.  
  935.                             DoIO(FlatNode -> fn_DiskRequest);
  936.  
  937.                             ReturnPacket(FlatPacket,DOSTRUE,NULL,HandlerProc);
  938.                         }
  939.                         else
  940.                             ReturnPacket(FlatPacket,DOSFALSE,ERROR_NO_FREE_STORE,HandlerProc);
  941.                     }
  942.                     else
  943.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  944.  
  945.                     break;
  946.  
  947.                     /* Close a file opened above. */
  948.  
  949.                 case ACTION_END:
  950.  
  951.                     DB(kprintf("ACTION_END\n"));
  952.  
  953.                         /* Find the node. */
  954.  
  955.                     if(FlatNode = FindFlatNodeByID(FlatPacket -> dp_Arg1))
  956.                     {
  957.                             /* Turn off the motor. */
  958.  
  959.                         FlatNode -> fn_DiskRequest -> iotd_Req . io_Command    = TD_MOTOR;
  960.                         FlatNode -> fn_DiskRequest -> iotd_Req . io_Length    = 0;
  961.  
  962.                         DoIO(FlatNode -> fn_DiskRequest);
  963.  
  964.                         Remove((struct Node *)FlatNode);
  965.  
  966.                         DeleteNode(FlatNode);
  967.                     }
  968.  
  969.                     ReturnPacket(FlatPacket,DOSTRUE,NULL,HandlerProc);
  970.                     break;
  971.  
  972.                     /* Read a couple of bytes from a file. */
  973.  
  974.                 case ACTION_READ:
  975.  
  976.                     DB(kprintf("ACTION_READ\n"));
  977.  
  978.                         /* Do we have a valid filehandle? */
  979.  
  980.                     if(FlatNode = FindFlatNodeByID(FlatPacket -> dp_Arg1))
  981.                     {
  982.                         LONG Res1,Res2 = NULL;
  983.  
  984.                         ReadBytes = FlatPacket -> dp_Arg3;
  985.  
  986.                             /* Reading across the data media size? */
  987.  
  988.                         if(FlatNode -> fn_Position + ReadBytes > (FlatNode -> fn_BlockSize * FlatNode -> fn_NumBlocks))
  989.                         {
  990.                             if((ReadBytes = FlatNode -> fn_BlockSize * FlatNode -> fn_NumBlocks - FlatNode -> fn_Position) < 0)
  991.                             {
  992.                                 ReadBytes = -1;
  993.  
  994.                                 Res2 = ERROR_SEEK_ERROR;
  995.                             }
  996.                         }
  997.  
  998.                             /* Read a few bytes. */
  999.  
  1000.                         if(ReadBytes > 0)
  1001.                         {
  1002.                             if((Bytes = DoRead(FlatNode,&Res2,ReadBytes,(APTR)FlatPacket -> dp_Arg2,FlatPacket -> dp_Port -> mp_SigTask)) > 0)
  1003.                                 FlatNode -> fn_Position += Bytes;
  1004.  
  1005.                             Res1 = Bytes;
  1006.                         }
  1007.                         else
  1008.                             Res1 = 0;
  1009.  
  1010.                         ReturnPacket(FlatPacket,Res1,Res2,HandlerProc);
  1011.                     }
  1012.                     else
  1013.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_WRONG_TYPE,HandlerProc);
  1014.  
  1015.                     break;
  1016.  
  1017.                     /* Write a few bytes to a file. */
  1018.  
  1019.                 case ACTION_WRITE:
  1020.  
  1021.                     DB(kprintf("ACTION_WRITE\n"));
  1022.  
  1023.                     if(FlatNode = FindFlatNodeByID(FlatPacket -> dp_Arg1))
  1024.                     {
  1025.                         LONG Res1,Res2 = NULL;
  1026.  
  1027.                         WriteBytes = FlatPacket -> dp_Arg3;
  1028.  
  1029.                         if(FlatNode -> fn_Position + WriteBytes > (FlatNode -> fn_BlockSize * FlatNode -> fn_NumBlocks))
  1030.                         {
  1031.                             if((WriteBytes = FlatNode -> fn_BlockSize * FlatNode -> fn_NumBlocks - FlatNode -> fn_Position) < 0)
  1032.                             {
  1033.                                 WriteBytes = -1;
  1034.  
  1035.                                 Res2 = ERROR_DISK_FULL;
  1036.                             }
  1037.                         }
  1038.  
  1039.                         if(WriteBytes > 0)
  1040.                         {
  1041.                             if((Bytes = DoWrite(FlatNode,&Res2,WriteBytes,(APTR)FlatPacket -> dp_Arg2,FlatPacket -> dp_Port -> mp_SigTask)) > 0)
  1042.                                 FlatNode -> fn_Position += Bytes;
  1043.  
  1044.                             Res1 = Bytes;
  1045.                         }
  1046.                         else
  1047.                             Res1 = 0;
  1048.  
  1049.                         ReturnPacket(FlatPacket,Res1,Res2,HandlerProc);
  1050.                     }
  1051.                     else
  1052.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_WRONG_TYPE,HandlerProc);
  1053.  
  1054.                     break;
  1055.  
  1056.                     /* Move the r/w pointer inside a file. */
  1057.  
  1058.                 case ACTION_SEEK:
  1059.  
  1060.                     DB(kprintf("ACTION_SEEK\n"));
  1061.  
  1062.                     if(FlatNode = FindFlatNodeByID(FlatPacket -> dp_Arg1))
  1063.                     {
  1064.                         LONG Res1,Res2 = NULL;
  1065.  
  1066.                         if(FlatPacket -> dp_Arg3 == OFFSET_BEGINNING)
  1067.                             NewPosition = FlatPacket -> dp_Arg2;
  1068.  
  1069.                         if(FlatPacket -> dp_Arg3 == OFFSET_CURRENT)
  1070.                             NewPosition = FlatNode -> fn_Position + FlatPacket -> dp_Arg2;
  1071.  
  1072.                         if(FlatPacket -> dp_Arg3 == OFFSET_END)
  1073.                             NewPosition = (FlatNode -> fn_BlockSize * FlatNode -> fn_NumBlocks) - FlatPacket -> dp_Arg2;
  1074.  
  1075.                         if(NewPosition < 0 || NewPosition > (FlatNode -> fn_BlockSize * FlatNode -> fn_NumBlocks))
  1076.                         {
  1077.                             Res1 = -1;
  1078.                             Res2 = ERROR_SEEK_ERROR;
  1079.                         }
  1080.                         else
  1081.                         {
  1082.                             Res1 = FlatNode -> fn_Position;
  1083.  
  1084.                             FlatNode -> fn_Position = NewPosition;
  1085.                         }
  1086.  
  1087.                         ReturnPacket(FlatPacket,Res1,Res2,HandlerProc);
  1088.                     }
  1089.                     else
  1090.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_WRONG_TYPE,HandlerProc);
  1091.  
  1092.                     break;
  1093.  
  1094.                     /* Remove the handler. */
  1095.  
  1096.                 case ACTION_DIE:
  1097.  
  1098.                     DB(kprintf("ACTION_DIE\n"));
  1099.  
  1100.                         /* Are we allowed to remove ourselves? */
  1101.  
  1102.                     if(!FlatList . lh_Head -> ln_Succ)
  1103.                     {
  1104.                         ReturnPacket(FlatPacket,DOSTRUE,0,HandlerProc);
  1105.  
  1106.                         goto FallOff;
  1107.                     }
  1108.                     else
  1109.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_IN_USE,HandlerProc);
  1110.  
  1111.                     break;
  1112.  
  1113.                     /* Ignore the rest of the packets. */
  1114.  
  1115.                 default:
  1116.  
  1117.                     DB(kprintf("dp_Type %ld\n",FlatPacket -> dp_Type));
  1118.                     DB(kprintf("dp_Arg1 0x%08lx\n",FlatPacket -> dp_Arg1));
  1119.                     DB(kprintf("dp_Arg2 0x%08lx\n",FlatPacket -> dp_Arg2));
  1120.                     DB(kprintf("dp_Arg3 0x%08lx\n",FlatPacket -> dp_Arg3));
  1121.                     DB(kprintf("dp_Arg4 0x%08lx\n",FlatPacket -> dp_Arg4));
  1122.                     DB(kprintf("dp_Arg5 0x%08lx\n",FlatPacket -> dp_Arg5));
  1123.                     DB(kprintf("dp_Arg6 0x%08lx\n",FlatPacket -> dp_Arg6));
  1124.                     DB(kprintf("dp_Arg7 0x%08lx\n",FlatPacket -> dp_Arg7));
  1125.  
  1126.                     ReturnPacket(FlatPacket,DOSFALSE,ERROR_ACTION_NOT_KNOWN,HandlerProc);
  1127.                     break;
  1128.             }
  1129.  
  1130.             DB(kprintf("\n"));
  1131.         }
  1132.  
  1133.             /* Cease actions, close libraries and exit. */
  1134.  
  1135. FallOff:    Forbid();
  1136.  
  1137.         if(VolumeNode)
  1138.         {
  1139.             struct DosInfo        *DosInfo;
  1140.             struct DeviceNode    *DevNode;
  1141.  
  1142.             DosInfo = (struct DosInfo *)(((struct RootNode *)DOSBase -> dl_Root) -> rn_Info);
  1143.  
  1144.             DevNode = (struct DeviceNode *)(BADDR(DosInfo -> di_DevInfo));
  1145.  
  1146.             while(DevNode)
  1147.             {
  1148.                 if(DevNode -> dn_Next = MKBADDR(VolumeNode))
  1149.                 {
  1150.                     DevNode -> dn_Next = VolumeNode -> dl_Next;
  1151.  
  1152.                     break;
  1153.                 }
  1154.                 else
  1155.                     DevNode = (struct DeviceNode *)BADDR(DevNode -> dn_Next);
  1156.             }
  1157.  
  1158.             VolumeNode -> dl_Task        = NULL;
  1159.             VolumeNode -> dl_DiskType    = ID_NO_DISK_PRESENT;
  1160.         }
  1161.  
  1162.         FlatDevNode -> dn_Task = NULL;
  1163.  
  1164.         if(FlatDevNode -> dn_SegList)
  1165.         {
  1166.             UnLoadSeg(FlatDevNode -> dn_SegList);
  1167.  
  1168.             FlatDevNode -> dn_SegList = NULL;
  1169.         }
  1170.  
  1171.         if(DiskPort)
  1172.             DeletePort(DiskPort);
  1173.  
  1174.         if(IntuitionBase)
  1175.             CloseLibrary(IntuitionBase);
  1176.  
  1177.         if(DOSBase)
  1178.             CloseLibrary(DOSBase);
  1179.  
  1180.         return(0);
  1181.     }
  1182.     else
  1183.         return(RETURN_FAIL);
  1184. }
  1185.  
  1186.     /* BaseName(UBYTE *String):
  1187.      *
  1188.      *    Returns the base of a filename.
  1189.      */
  1190.  
  1191. UBYTE * __regargs
  1192. BaseName(UBYTE *String)
  1193. {
  1194.     if(String[0])
  1195.     {
  1196.         WORD i;
  1197.  
  1198.         for(i = strlen(String) - 1 ; i >= 0 ; i--)
  1199.         {
  1200.             if(String[i] == ':' || String[i] == '/')
  1201.             {
  1202.                 if(String[i + 1])
  1203.                     return(&String[i + 1]);
  1204.                 else
  1205.                     return(NULL);
  1206.             }
  1207.         }
  1208.  
  1209.         return(String);
  1210.     }
  1211.     else
  1212.         return(NULL);
  1213. }
  1214.  
  1215.     /* Local2Upper(UBYTE c):
  1216.      *
  1217.      *    Convert a character to upper case.
  1218.      */
  1219.  
  1220. UBYTE __regargs
  1221. Local2Upper(UBYTE c)
  1222. {
  1223.     return((UBYTE)((((c) >= 224 && (c) <= 254) || ((c) >= 'a' && (c) <= 'z')) ? (c) - 32 : c));
  1224. }
  1225.  
  1226.     /* StrCmp(UBYTE *a,UBYTE *b):
  1227.      *
  1228.      *    Do string comparison ignoring case.
  1229.      */
  1230.  
  1231. UBYTE __regargs
  1232. StrCmp(UBYTE *a,UBYTE *b)
  1233. {
  1234.     LONG Len = strlen(a);
  1235.  
  1236.     if(Len != strlen(b))
  1237.         return(1);
  1238.     else
  1239.     {
  1240.         if(Len)
  1241.         {
  1242.             do
  1243.             {
  1244.                 if(Local2Upper(*a++) != Local2Upper(*b++))
  1245.                     return(1);
  1246.             }
  1247.             while(--Len);
  1248.         }
  1249.  
  1250.         return(0);
  1251.     }
  1252. }
  1253.  
  1254.     /* FindFlatNodeByID(ULONG UniqueID):
  1255.      *
  1256.      *    Scan the item list looking for a list entry with
  1257.      *    a matching ID.
  1258.      */
  1259.  
  1260. struct FlatNode * __regargs
  1261. FindFlatNodeByID(ULONG UniqueID)
  1262. {
  1263.     struct FlatNode *Node;
  1264.  
  1265.     Node = (struct FlatNode *)FlatList . lh_Head;
  1266.  
  1267.     while(Node -> fn_Succ)
  1268.     {
  1269.         if(Node -> fn_UniqueID == UniqueID)
  1270.             return(Node);
  1271.  
  1272.         Node = Node -> fn_Succ;
  1273.     }
  1274.  
  1275.     return(NULL);
  1276. }
  1277.  
  1278.     /* FindFlatNodeByName(UBYTE *Name):
  1279.      *
  1280.      *    Scan the item list looking for an entry with a
  1281.      *    matching name.
  1282.      */
  1283.  
  1284. struct FlatNode * __regargs
  1285. FindFlatNodeByName(UBYTE *Name)
  1286. {
  1287.     struct FlatNode *Node;
  1288.  
  1289.     for(Node = (struct FlatNode *)FlatList . lh_Head ; Node -> fn_Succ ; Node = Node -> fn_Succ)
  1290.     {
  1291.         if(!StrCmp(&Node -> fn_Name[1],Name))
  1292.             return(Node);
  1293.     }
  1294.  
  1295.     return(NULL);
  1296. }
  1297.  
  1298.     /* BtoCStr(UBYTE *Name,BSTR String,LONG MaxLength):
  1299.      *
  1300.      *    Convert a BCPL string into a `C' string.
  1301.      */
  1302.  
  1303. VOID __regargs
  1304. BtoCStr(UBYTE *Name,BSTR String,LONG MaxLength)
  1305. {
  1306.     UBYTE *Src,Length;
  1307.  
  1308.     if(Src = (UBYTE *)BADDR(String))
  1309.     {
  1310.         if((Length = Src[0]) > MaxLength)
  1311.             Length = MaxLength;
  1312.  
  1313.         Src++;
  1314.  
  1315.         while(Length--)
  1316.             *Name++ = *Src++;
  1317.  
  1318.         *Name = 0;
  1319.     }
  1320. }
  1321.  
  1322.     /* ShowRequest(APTR WindowPtr,BYTE Type,UBYTE *Drive):
  1323.      *
  1324.      *    If trouble shows up, behave like the standard
  1325.      *    FS and complain.
  1326.      */
  1327.  
  1328. LONG __regargs
  1329. ShowRequest(APTR WindowPtr,BYTE Type,UBYTE *Drive)
  1330. {
  1331.     STATIC struct IntuiText DiskWriteProtected[3] =
  1332.     {
  1333.         {0,1,JAM2,15, 5,NULL,"Disk in drive",                &DiskWriteProtected[1]},
  1334.         {0,1,JAM2,15,15,NULL,"################################",    &DiskWriteProtected[2]},
  1335.         {0,1,JAM2,15,25,NULL,"is write protected",            NULL}
  1336.     };
  1337.  
  1338.     STATIC struct IntuiText DiskNotPresent[2] =
  1339.     {
  1340.         {0,1,JAM2,15, 5,NULL,"No disk present in drive",        &DiskNotPresent[1]},
  1341.         {0,1,JAM2,15,15,NULL,"################################",    NULL}
  1342.     };
  1343.  
  1344.     STATIC struct IntuiText DiskUnreadable[3] =
  1345.     {
  1346.         {0,1,JAM2,15, 5,NULL,"Disk in drive",                &DiskUnreadable[1]},
  1347.         {0,1,JAM2,15,15,NULL,"################################",    &DiskUnreadable[2]},
  1348.         {0,1,JAM2,15,25,NULL,"is unreadable",                NULL}
  1349.     };
  1350.  
  1351.     STATIC struct IntuiText DiskWriteError[2] =
  1352.     {
  1353.         {0,1,JAM2,15, 5,NULL,"Error writing to drive",            &DiskWriteError[1]},
  1354.         {0,1,JAM2,15,15,NULL,"################################",    NULL}
  1355.     };
  1356.  
  1357.     STATIC struct IntuiText Retry =
  1358.     {
  1359.         0,1,JAM2,7,3,NULL,"Retry",NULL
  1360.     };
  1361.  
  1362.     STATIC struct IntuiText Cancel =
  1363.     {
  1364.         0,1,JAM2,7,3,NULL,"Cancel",NULL
  1365.     };
  1366.  
  1367.         /* A -1 will result in cancelling the
  1368.          * requester.
  1369.          */
  1370.  
  1371.     if(WindowPtr != (APTR)-1)
  1372.     {
  1373.         struct IntuiText    *BodyText;
  1374.         WORD             i;
  1375.  
  1376.             /* Install the right alert type. */
  1377.  
  1378.         switch(Type)
  1379.         {
  1380.             case ERR_WRITEPROTECT:    BodyText = DiskWriteProtected;
  1381.                         break;
  1382.  
  1383.             case ERR_NODISK:    BodyText = DiskNotPresent;
  1384.                         break;
  1385.  
  1386.             case ERR_UNREADABLE:    BodyText = DiskUnreadable;
  1387.                         break;
  1388.  
  1389.             case ERR_WRITEERROR:    BodyText = DiskWriteError;
  1390.                         break;
  1391.         }
  1392.  
  1393.             /* Add the drive name. */
  1394.  
  1395.         for(i = 0 ; BodyText[1] . IText[i] = Local2Upper(Drive[i + 1]) ; i++);
  1396.  
  1397.             /* Show the requester. */
  1398.  
  1399.         return((LONG)AutoRequest(WindowPtr,BodyText,&Retry,&Cancel,DISKINSERTED,NULL,320,72));
  1400.     }
  1401.  
  1402.     return(FALSE);
  1403. }
  1404.  
  1405.     /* FindDevice():
  1406.      *
  1407.      *    Find a DeviceNode entry in the DosList.
  1408.      */
  1409.  
  1410. struct DeviceNode * __regargs
  1411. FindDevice(struct DeviceNode *LastNode,struct FileSysStartupMsg    **Startup,struct DosEnvec **DosEnvec,UBYTE *Name)
  1412. {
  1413.     struct DeviceNode    *DevInfo;
  1414.     STATIC UBYTE         NameBuffer[257];
  1415.  
  1416.     Forbid();
  1417.  
  1418.     if(LastNode)
  1419.         DevInfo = (struct DeviceNode *)BADDR(LastNode -> dn_Next);
  1420.     else
  1421.         DevInfo = (struct DeviceNode *)BADDR(((struct DosInfo *)BADDR(((struct RootNode *)DOSBase -> dl_Root) -> rn_Info)) -> di_DevInfo);
  1422.  
  1423.     while(DevInfo)
  1424.     {
  1425.         if(DevInfo -> dn_Type == DLT_DEVICE && DevInfo -> dn_Task && DevInfo -> dn_Startup)
  1426.         {
  1427.             if(TypeOfMem(DevInfo -> dn_Task) && TypeOfMem(BADDR(DevInfo -> dn_Startup)))
  1428.             {
  1429.                 struct DosEnvec *Environ = (struct DosEnvec *)BADDR(((struct FileSysStartupMsg *)BADDR(DevInfo -> dn_Startup)) -> fssm_Environ);
  1430.  
  1431.                 if(TypeOfMem(Environ))
  1432.                 {
  1433.                     if(Name)
  1434.                     {
  1435.                         BtoCStr(NameBuffer,DevInfo -> dn_Name,256);
  1436.  
  1437.                         if(!StrCmp(NameBuffer,Name))
  1438.                         {
  1439.                             if(Startup)
  1440.                                 *Startup = (struct FileSysStartupMsg *)BADDR(DevInfo -> dn_Startup);
  1441.  
  1442.                             if(DosEnvec)
  1443.                                 *DosEnvec = Environ;
  1444.  
  1445.                             Permit();
  1446.  
  1447.                             return(DevInfo);
  1448.                         }
  1449.                     }
  1450.                     else
  1451.                     {
  1452.                         if(Startup)
  1453.                             *Startup = (struct FileSysStartupMsg *)BADDR(DevInfo -> dn_Startup);
  1454.  
  1455.                         if(DosEnvec)
  1456.                             *DosEnvec = Environ;
  1457.  
  1458.                         Permit();
  1459.  
  1460.                         return(DevInfo);
  1461.                     }
  1462.                 }
  1463.             }
  1464.         }
  1465.  
  1466.         DevInfo = (struct DeviceNode *)BADDR(DevInfo -> dn_Next);
  1467.     }
  1468.  
  1469.     Permit();
  1470.  
  1471.     return(NULL);
  1472. }
  1473.  
  1474.     /* DeleteNode(struct FlatNode *FlatNode):
  1475.      *
  1476.      *    Delete a freshly created item node freeing
  1477.      *    all associated resources.
  1478.      */
  1479.  
  1480. VOID __regargs
  1481. DeleteNode(struct FlatNode *FlatNode)
  1482. {
  1483.     if(FlatNode -> fn_DiskBuffer)
  1484.         FreeMem(FlatNode -> fn_DiskBuffer,FlatNode -> fn_BlockSize);
  1485.  
  1486.     if(FlatNode -> fn_DiskRequest)
  1487.     {
  1488.         if(FlatNode -> fn_DiskRequest -> iotd_Req . io_Device)
  1489.         {
  1490.                      FlatNode -> fn_DiskRequest -> iotd_Req . io_Command = CMD_UPDATE;
  1491.  
  1492.             DoIO(FlatNode -> fn_DiskRequest);
  1493.  
  1494.                      FlatNode -> fn_DiskRequest -> iotd_Req . io_Command    = TD_MOTOR;
  1495.                      FlatNode -> fn_DiskRequest -> iotd_Req . io_Length    = 0;
  1496.  
  1497.             DoIO(FlatNode -> fn_DiskRequest);
  1498.  
  1499.             CloseDevice(FlatNode -> fn_DiskRequest);
  1500.         }
  1501.  
  1502.         DeleteExtIO(FlatNode -> fn_DiskRequest);
  1503.     }
  1504.  
  1505.     FreeMem(FlatNode,sizeof(struct FlatNode));
  1506. }
  1507.  
  1508.     /* CreateNode(struct MsgPort *DiskPort,LONG Type,UBYTE *Name):
  1509.      *
  1510.      *    Create an item node with given characteristics,
  1511.      *    can be either shared or exclusive access, if a name
  1512.      *    is given will open the approriate device driver.
  1513.      */
  1514.  
  1515. struct FlatNode * __regargs
  1516. CreateNode(struct MsgPort *DiskPort,LONG Type,UBYTE *Name)
  1517. {
  1518.     struct FlatNode *FlatNode;
  1519.  
  1520.     if(FlatNode = (struct FlatNode *)AllocMem(sizeof(struct FlatNode),MEMF_PUBLIC|MEMF_CLEAR))
  1521.     {
  1522.         if(Name)
  1523.         {
  1524.             struct DeviceNode        *DevInfo;
  1525.             struct FileSysStartupMsg    *Startup;
  1526.             struct DosEnvec            *DosEnvec;
  1527.  
  1528.                 /* Try to find the device. */
  1529.  
  1530.             if(!(DevInfo = FindDevice(NULL,&Startup,&DosEnvec,Name)))
  1531.             {
  1532.                 DeleteNode(FlatNode);
  1533.  
  1534.                 return(NULL);
  1535.             }
  1536.  
  1537.                 /* Create a device request. */
  1538.  
  1539.             if(!(FlatNode -> fn_DiskRequest = (struct IOExtTD *)CreateExtIO(DiskPort,sizeof(struct IOExtTD))))
  1540.             {
  1541.                 DeleteNode(FlatNode);
  1542.  
  1543.                 return(NULL);
  1544.             }
  1545.  
  1546.                 /* Open the device driver. */
  1547.  
  1548.             if(OpenDevice(&((UBYTE *)BADDR(Startup -> fssm_Device))[1],Startup -> fssm_Unit,FlatNode -> fn_DiskRequest,Startup -> fssm_Flags))
  1549.             {
  1550.                 DeleteNode(FlatNode);
  1551.  
  1552.                 return(NULL);
  1553.             }
  1554.  
  1555.                 /* Inquire the unit data. */
  1556.  
  1557.             FlatNode -> fn_BlockSize    = DosEnvec -> de_SizeBlock << 2;
  1558.             FlatNode -> fn_FirstBlock    = DosEnvec -> de_LowCyl * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces;
  1559.             FlatNode -> fn_NumBlocks    = (DosEnvec -> de_HighCyl - DosEnvec -> de_LowCyl + 1) * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces;
  1560.  
  1561.                 /* Create a r/w buffer. */
  1562.  
  1563.             if(!(FlatNode -> fn_DiskBuffer = (APTR)AllocMem(FlatNode -> fn_BlockSize,DosEnvec -> de_BufMemType)))
  1564.             {
  1565.                 DeleteNode(FlatNode);
  1566.  
  1567.                 return(NULL);
  1568.             }
  1569.  
  1570.             strcpy(&FlatNode -> fn_Name[1],Name);
  1571.         }
  1572.  
  1573.         FlatNode -> fn_Mode    = Type;
  1574.         FlatNode -> fn_UniqueID    = UniqueCounter++;
  1575.     }
  1576.  
  1577.     return(FlatNode);
  1578. }
  1579.  
  1580.     /* ReturnPacket():
  1581.      *
  1582.      *    Return a standard DOS packet to its sender.
  1583.      */
  1584.  
  1585. VOID __regargs
  1586. ReturnPacket(struct DosPacket *Packet,ULONG Res1,ULONG Res2,struct Process *HandlerProc)
  1587. {
  1588.     struct MsgPort *ReplyPort;
  1589.  
  1590.     DB(kprintf("Return: %lx,%lx\n",Res1,Res2));
  1591.  
  1592.     ReplyPort = Packet -> dp_Port;
  1593.  
  1594.     Packet -> dp_Res1 = Res1;
  1595.     Packet -> dp_Res2 = Res2;
  1596.  
  1597.     Packet -> dp_Port = &HandlerProc -> pr_MsgPort;
  1598.  
  1599.     Packet -> dp_Link -> mn_Node . ln_Name    = (APTR)Packet;
  1600.     Packet -> dp_Link -> mn_Node . ln_Succ    = NULL;
  1601.     Packet -> dp_Link -> mn_Node . ln_Pred    = NULL;
  1602.  
  1603.     PutMsg(ReplyPort,Packet -> dp_Link);
  1604. }
  1605.  
  1606.     /* WaitPacket(struct Process *HandlerProc):
  1607.      *
  1608.      *    Wait for packet arrival.
  1609.      */
  1610.  
  1611. struct DosPacket * __regargs
  1612. WaitPacket(struct Process *HandlerProc)
  1613. {
  1614.     struct Message *DOSMsg;
  1615.  
  1616.     WaitPort(&HandlerProc -> pr_MsgPort);
  1617.  
  1618.     DOSMsg = (struct Message *)GetMsg(&HandlerProc -> pr_MsgPort);
  1619.  
  1620.     return((struct DosPacket *)DOSMsg -> mn_Node . ln_Name);
  1621. }
  1622.  
  1623.     /* DoRead():
  1624.      *
  1625.      *    Read a few bytes from a file.
  1626.      */
  1627.  
  1628. LONG __regargs
  1629. DoRead(struct FlatNode *FlatNode,LONG *Error,LONG Size,UBYTE *Buffer,struct Process *Caller)
  1630. {
  1631.     LONG Block,Length,BytesRead = 0,Offset = FlatNode -> fn_Position;
  1632.     UBYTE *DiskBuffer = FlatNode -> fn_DiskBuffer;
  1633.  
  1634.         /* Time for a check? */
  1635.  
  1636.     if(!FlatNode -> fn_CheckCount)
  1637.     {
  1638.         FOREVER
  1639.         {
  1640.             FlatNode -> fn_DiskRequest -> iotd_Req . io_Command = TD_CHANGESTATE;
  1641.  
  1642.                 /* Is there still a disk in the drive? */
  1643.  
  1644.             if(!DoIO(FlatNode -> fn_DiskRequest))
  1645.             {
  1646.                 if(FlatNode -> fn_DiskRequest -> iotd_Req . io_Actual)
  1647.                 {
  1648.                     if(!ShowRequest(Caller -> pr_WindowPtr,ERR_NODISK,&FlatNode -> fn_Name[1]))
  1649.                     {
  1650.                         *Error = ERROR_NO_DISK;
  1651.  
  1652.                         return(0);
  1653.                     }
  1654.                 }
  1655.                 else
  1656.                     break;
  1657.             }
  1658.         }
  1659.     }
  1660.  
  1661.     if(FlatNode -> fn_CheckCount++ == 10)
  1662.         FlatNode -> fn_CheckCount = 0;
  1663.  
  1664.         /* Convert offset from bytes into blocks. */
  1665.  
  1666.     Block    = Offset / FlatNode -> fn_BlockSize;
  1667.     Offset    = Offset % FlatNode -> fn_BlockSize;
  1668.  
  1669.     if(Size > 0)
  1670.     {
  1671.             /* Read the data block by block... */
  1672.  
  1673.         while(Size > 0)
  1674.         {
  1675. Retry:            FlatNode -> fn_DiskRequest -> iotd_Req . io_Command    = CMD_READ;
  1676.             FlatNode -> fn_DiskRequest -> iotd_Req . io_Offset    = Block * FlatNode -> fn_BlockSize + FlatNode -> fn_FirstBlock * FlatNode -> fn_BlockSize;
  1677.             FlatNode -> fn_DiskRequest -> iotd_Req . io_Length    = FlatNode -> fn_BlockSize;
  1678.             FlatNode -> fn_DiskRequest -> iotd_Req . io_Data    = DiskBuffer;
  1679.  
  1680.                 /* Read the block. */
  1681.  
  1682.             if(DoIO(FlatNode -> fn_DiskRequest))
  1683.             {
  1684.                 if(ShowRequest(Caller -> pr_WindowPtr,ERR_UNREADABLE,&FlatNode -> fn_Name[1]))
  1685.                     goto Retry;
  1686.                 else
  1687.                 {
  1688.                     *Error = FlatNode -> fn_DiskRequest -> iotd_Req . io_Error;
  1689.  
  1690.                     return(BytesRead);
  1691.                 }
  1692.             }
  1693.  
  1694.             Length = FlatNode -> fn_BlockSize - Offset;
  1695.  
  1696.             if(Length > Size)
  1697.                 Length = Size;
  1698.  
  1699.                 /* Copy the data. */
  1700.  
  1701.             memcpy(Buffer,&DiskBuffer[Offset],Length);
  1702.  
  1703.             Buffer = &Buffer[Length];
  1704.  
  1705.             Size -= Length;
  1706.  
  1707.             BytesRead += Length;
  1708.  
  1709.             Block++;
  1710.  
  1711.             Offset = 0;
  1712.         }
  1713.     }
  1714.  
  1715.     return(BytesRead);
  1716. }
  1717.  
  1718.     /* DoWrite():
  1719.      *
  1720.      *    Write a few bytes to a file.
  1721.      */
  1722.  
  1723. LONG __regargs
  1724. DoWrite(struct FlatNode *FlatNode,LONG *Error,LONG Size,UBYTE *Buffer,struct Process *Caller)
  1725. {
  1726.     LONG Block,Length,BytesWritten = 0,Offset = FlatNode -> fn_Position;
  1727.     UBYTE *DiskBuffer = FlatNode -> fn_DiskBuffer;
  1728.  
  1729.         /* Time for a check? */
  1730.  
  1731.     if(!FlatNode -> fn_CheckCount)
  1732.     {
  1733.         FOREVER
  1734.         {
  1735.             FlatNode -> fn_DiskRequest -> iotd_Req . io_Command = TD_CHANGESTATE;
  1736.  
  1737.                 /* Is there a disk in the drive? */
  1738.  
  1739.             if(!DoIO(FlatNode -> fn_DiskRequest))
  1740.             {
  1741.                 if(FlatNode -> fn_DiskRequest -> iotd_Req . io_Actual)
  1742.                 {
  1743.                     if(!ShowRequest(Caller -> pr_WindowPtr,ERR_NODISK,&FlatNode -> fn_Name[1]))
  1744.                     {
  1745.                         *Error = ERROR_NO_DISK;
  1746.  
  1747.                         return(0);
  1748.                     }
  1749.                 }
  1750.                 else
  1751.                     break;
  1752.             }
  1753.         }
  1754.  
  1755.         FOREVER
  1756.         {
  1757.             FlatNode -> fn_DiskRequest -> iotd_Req . io_Command = TD_PROTSTATUS;
  1758.  
  1759.                 /* Is the disk write enabled? */
  1760.  
  1761.             if(!DoIO(FlatNode -> fn_DiskRequest))
  1762.             {
  1763.                 if(FlatNode -> fn_DiskRequest -> iotd_Req . io_Actual)
  1764.                 {
  1765.                     if(!ShowRequest(Caller -> pr_WindowPtr,ERR_WRITEPROTECT,&FlatNode -> fn_Name[1]))
  1766.                     {
  1767.                         *Error = ERROR_DISK_WRITE_PROTECTED;
  1768.  
  1769.                         return(0);
  1770.                     }
  1771.                 }
  1772.                 else
  1773.                     break;
  1774.             }
  1775.         }
  1776.     }
  1777.  
  1778.     if(FlatNode -> fn_CheckCount++ == 10)
  1779.         FlatNode -> fn_CheckCount = 0;
  1780.  
  1781.         /* Convert offset from bytes into blocks. */
  1782.  
  1783.     Block    = Offset / FlatNode -> fn_BlockSize;
  1784.     Offset    = Offset % FlatNode -> fn_BlockSize;
  1785.  
  1786.     if(Size > 0)
  1787.     {
  1788.         while(Size > 0)
  1789.         {
  1790. Retry1:            if(Offset)
  1791.             {
  1792.                     /* The data to write is smaller
  1793.                      * than a block, so we'll have to
  1794.                      * read the block to write to first,
  1795.                      * copy the data over and write the
  1796.                      * block back.
  1797.                      */
  1798.  
  1799.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Command    = CMD_READ;
  1800.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Offset    = Block * FlatNode -> fn_BlockSize + FlatNode -> fn_FirstBlock * FlatNode -> fn_BlockSize;
  1801.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Length    = FlatNode -> fn_BlockSize;
  1802.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Data    = DiskBuffer;
  1803.  
  1804.                 if(DoIO(FlatNode -> fn_DiskRequest))
  1805.                 {
  1806.                     if(ShowRequest(Caller -> pr_WindowPtr,ERR_UNREADABLE,&FlatNode -> fn_Name[1]))
  1807.                         goto Retry1;
  1808.                     else
  1809.                     {
  1810.                         *Error = FlatNode -> fn_DiskRequest -> iotd_Req . io_Error;
  1811.  
  1812.                         return(BytesWritten);
  1813.                     }
  1814.                 }
  1815.  
  1816.                 Length = FlatNode -> fn_BlockSize - Offset;
  1817.  
  1818.                 if(Length > Size)
  1819.                     Length = Size;
  1820.  
  1821.                 memcpy(&DiskBuffer[Offset],Buffer,Length);
  1822.  
  1823. Retry2:                FlatNode -> fn_DiskRequest -> iotd_Req . io_Command    = CMD_WRITE;
  1824.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Offset    = Block * FlatNode -> fn_BlockSize + FlatNode -> fn_FirstBlock * FlatNode -> fn_BlockSize;
  1825.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Length    = FlatNode -> fn_BlockSize;
  1826.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Data    = DiskBuffer;
  1827.  
  1828.                 if(DoIO(FlatNode -> fn_DiskRequest))
  1829.                 {
  1830.                     if(ShowRequest(Caller -> pr_WindowPtr,ERR_WRITEERROR,&FlatNode -> fn_Name[1]))
  1831.                         goto Retry2;
  1832.                     else
  1833.                     {
  1834.                         *Error = FlatNode -> fn_DiskRequest -> iotd_Req . io_Error;
  1835.  
  1836.                         return(BytesWritten);
  1837.                     }
  1838.                 }
  1839.  
  1840.                 Buffer = &Buffer[Length];
  1841.  
  1842.                 Size -= Length;
  1843.  
  1844.                 BytesWritten += Length;
  1845.  
  1846.                 Block++;
  1847.  
  1848.                 Offset = 0;
  1849.             }
  1850.             else
  1851.             {
  1852.                 if(Size > FlatNode -> fn_BlockSize)
  1853.                     Length = FlatNode -> fn_BlockSize;
  1854.                 else
  1855.                 {
  1856.                     if(Size < FlatNode -> fn_BlockSize)
  1857.                         memset(DiskBuffer,0,FlatNode -> fn_BlockSize);
  1858.  
  1859.                     Length = Size;
  1860.                 }
  1861.  
  1862.                 memcpy(DiskBuffer,Buffer,Length);
  1863.  
  1864. Retry3:                FlatNode -> fn_DiskRequest -> iotd_Req . io_Command    = CMD_WRITE;
  1865.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Offset    = Block * FlatNode -> fn_BlockSize + FlatNode -> fn_FirstBlock * FlatNode -> fn_BlockSize;
  1866.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Length    = FlatNode -> fn_BlockSize;
  1867.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Data    = DiskBuffer;
  1868.  
  1869.                 if(DoIO(FlatNode -> fn_DiskRequest))
  1870.                 {
  1871.                     if(ShowRequest(Caller -> pr_WindowPtr,ERR_WRITEERROR,&FlatNode -> fn_Name[1]))
  1872.                         goto Retry1;
  1873.                     else
  1874.                     {
  1875.                         *Error = FlatNode -> fn_DiskRequest -> iotd_Req . io_Error;
  1876.  
  1877.                         return(BytesWritten);
  1878.                     }
  1879.                 }
  1880.  
  1881.                 Buffer = &Buffer[Length];
  1882.  
  1883.                 Size -= Length;
  1884.  
  1885.                 BytesWritten += Length;
  1886.  
  1887.                 Block++;
  1888.             }
  1889.         }
  1890.     }
  1891.  
  1892.     return(BytesWritten);
  1893. }
  1894.